<?
/**
 * php Socket邮件发送类
 * 
 * 提供用户邮件smtp发送,需要用户名和密码
 * @package     Class
 * @author      jerry <jerryjiang15@163.com>
 * @version     $ID$
 */
class SendMail
{
	var $smtp;             //smtp地址
	var $port;             //smtp端口号
	var $auth_username;    //smtp邮箱用户名
	var $auth_password;    //smtp邮箱密码
	var $host_name;        //主机名字
	var $return_info = array();  //是否显示调试信息      
	var $fp;               //socket句柄
	var $attachment = array();   //附件
	
	
	/**
	 * 构造函数
	 *
	 * @param string $smtp   smtp服务器地址
	 * @param int $port      端口号
	 * @param string $auth_username  登陆名
	 * @param string $auth_password  密码
	 * @param string $host_name    服务器名字
	 */
	function SendMail($smtp,$port = '25',$auth_username,$auth_password,$host_name = '')
	{
		$this->init($smtp,$port,$auth_username,$auth_password,$host_name);
	}
	
	function init($smtp,$port = '25',$auth_username,$auth_password,$host_name = '')
	{
		$this->smtp = $smtp;
		$this->port = $port;
		$this->auth_username = $auth_username;
		$this->auth_password = $auth_password;

		if(empty($host_name))
		{
			$this->host_name = gethostbyaddr($_SERVER['REMOTE_ADDR']);
		}
		else 
		{
			$this->host_name = $host_name;
		}
	}
	
	 function doCommand($command, $code)
    {
    	fputs($this->fp,$command);

    	$last_message = fgets ( $this->fp, 512 );
    	$error[command] = $command;
        $error[message] = $last_message;
        
        $this->return_info[] = $error;
       
        if(!ereg("^$code", $last_message))
        {
            return false;
        }
        else 
        {
        	return true;
        }
    }
    
    function addAttachment($file)
    {
    	if(file_exists($file))
    	{
    		$this->attachment[] = $file;
		}
		else 
		{
			die("The file $file does not exist");
		}
    }
    
    function clearAttachment()
    {
    	$this->attachment = '';
    }
    
    /**
     * Determine if a string contains 8-bit characters.
     * @access private
     *
     * @param string $string  The string to check.
     * @return boolean        true if it does, false if it doesn't.
     */
    function is8bit($string)
    {
        if (is_string($string)) 
        {
            for ($i = 0; $i < strlen($string); $i++) 
            {
                if (ord($string[$i]) >> 7)
                    return true;
            }
            return false;
        }
        return false;
    }
    
    
    /**
     * Encode a string containing non-ascii characters according to RFC 2047.
     *
     * @param string $text    The text to encode.
     * @param string $charset (optional) The character set of the text.
     * @param boolean $outer  Is this the final iteration?
     *
     * @return string The text, encoded only if it contains non-ascii characters.
     */
    function encode($text, $charset = null, $outer = true)
    {
        if ($this->is8bit($text)) {
            if (((strlen($text) * 3) + strlen($charset) + 7) > 76) {
                $text = $this->encode(substr($text, 0, (23 - strlen($charset))), $charset) . $this->encode(substr($text, (23 - strlen($charset))), $charset, false);
            } else {
                $text = "=?$charset?B?" . strtr(trim(base64_encode($text)), ' ', '_') . "?=\n\t";
            }
        }
        
        // if this is the final iteration, take off any trailing
        // newline/tab chars.
        if ($outer && (substr($text, -2) == "\n\t"))
            $text = substr($text, 0, -2);
        
        return $text;
    }
    
    function debug()
    {
    	print_r($this->return_info);
    }
    
    function getContentType($file_name)
    { 
		//--去除路径 
		$file_name = basename($file_name); 
		//--去除没有扩展名的文件 
		if(strrchr($file_name, ".") == false)
		{ 
			return "application/octet-stream"; 
		} 
		//--提区扩展名并进行判断 
		$extension = strrchr($file_name, "."); 
		
		switch($extension)
		{ 
			case ".gif": 
				return "image/gif"; 
			break;
			case ".gz": 
				return "application/x-gzip"; 
			break;
			case ".htm": 
				return "text/html"; 
			break;
			case ".html": 
				return "text/html"; 
			break;
			case ".jpg": 
				return "image/jpeg"; 
			break;
			case ".tar": 
				return "application/x-tar";
			break; 
			case ".txt": 
				return "text/plain"; 
			break;
			case ".zip": 
				return "application/zip"; 
			break;
			default: 
				return "application/octet-stream"; 
			break;
		} 
		
		return "application/octet-stream"; 
	} 


	function send($from,$auth = '',$to,$receiver,$subject,$message,$type = 'txt',$charset = 'gb2312')
	{
		$this->fp = fsockopen($this->smtp,$this->port,$errno,$errstr,120) or die("not to connection this server:$this->smtp");
		$this->return_info[] = $return = fgets($this->fp,512);
		//$this->return_info[] = $return = fgets($this->fp,512);
		if( !ereg("^220",$return) )   //判断服务器是否就绪
		{
			fclose($this->fp);
			return false;
		}
		
		if($this->doCommand("helo {$this->host_name}\r\n",'250') === false)   //与服务器打招呼
		{ 
			fclose($this->fp);
			return false;    
		}
		
		if($this->auth_username)
		{
			if($this->doCommand("auth login\r\n",'334') === false)   //开始确认用户和密码
			{
				fclose($this->fp);
				return false;    
			}
			
			if($this->doCommand(base64_encode("{$this->auth_username}")."\r\n",'334') === false)   //提交用戶名
			{
				fclose($this->fp);
				return false;    
			}
			
			if($this->doCommand(base64_encode("{$this->auth_password}")."\r\n",'235') === false)   //提交密码
			{
				fclose($this->fp);
				return false;    
			}
		}
		
		if($this->doCommand("MAIL FROM:<{$from}> \r\n",'250') === false)   //提交發信人EMAIL址
		{
			fclose($this->fp);
			return false;    
		}
		
		$to = explode(',',$to);
		
		foreach ($to as $value)
		{
			if($this->doCommand("RCPT TO:<{$value}> \r\n",'250') === false)   //提交收件EMAIL址
			{
				fclose($this->fp);
				return false;    
			}
		}
		
/*		if($this->doCommand("RCPT TO:<{$to}> \r\n",'250') === false)   //提交收件EMAIL址
		{
			fclose($this->fp);
			return false;    
		}
		*/
		if($this->doCommand("data\r\n",'354') === false)   //提交内容申请
		{
			fclose($this->fp);
			return false;    
		}
		
		$to_send = "Return-Path: <$from>\r\n";          //信件內容
		if(!empty($auth))                                    
		{
			$to_send .= "From: " . $this->encode($auth,$charset) . " <$from>\r\n";             
		}
		else 
		{
			$to_send .= "From: $from\r\n";
		}
		if(!empty($receiver)) 
		{
			if(count($to) == 1)
			{
				$to_send .= "To: " . $this->encode($receiver,$charset) . " <" . $to[0] . ">\r\n";
			}
			else 
			{
				$to_send .= "To: " . $this->encode($receiver,$charset) . " <everyone@anymail.com>\r\n";
			}
		}
		
		$to_send .= 'Subject: ' . $this->encode(str_replace("\n", ' ', $subject),$charset) . "\r\n"; 
		
		if(!empty($this->attachment))
    	{
    		$boundary = uniqid(""); 
    		$to_send .= "MIME-Version: 1.0\r\n";
    		$to_send .= "Content-Type: multipart/mixed; boundary=\"$boundary\"\r\n";
    		$to_send .= "This is a multi-part message in MIME format.";
    		$to_send .= "\r\n\r\n--$boundary\r\n";
    	}
    	
    	if($type == 'txt')
		{
			$to_send .= "Content-type: text/plain;";
		}
		else 
		{
			$to_send .= "Content-type: text/html;";
		}
		
    	$to_send .= "charset=$charset\r\n";
    	$to_send .= "Content-transfer-encoding: 8bit\r\n"; 
		
    	if(empty($this->attachment))
    	{
    		$to_send .= "\r\n$message\r\n.\r\n";
    	}
		else
		{
			$to_send .= "\r\n$message\r\n\r\n";
		}
		
		if(!empty($this->attachment))
    	{
    		foreach ($this->attachment as $key=>$value)
    		{
    			
    			# 确定上传文件的MIME类型 
				$mime_type = $this->getContentType($value);
				
				# 确定文件的名字 
				$attachment_name = str_replace("\\","/" , $value);
				$attachment_name = explode('/' , $attachment_name);
				$file_name = end($attachment_name);
				
				# 打开文件 
				$fp = fopen($value, "r"); 
				# 把整个文件读入一个变量 
				$read = fread($fp, filesize($value)); 
				
				# 好，现在变量$read中保存的是包含整个文件内容的文本块。
				# 现在我们要把这个文本块转换成邮件程序可以读懂的格式 
				# 我们用base64方法把它编码 
				$read = base64_encode($read); 
				
				# 现在我们有一个用base64方法编码的长字符串。 
				# 下一件事是要把这个长字符串切成由每行76个字符组成的小块 
				$read = chunk_split($read);
				
				$to_send .= "--$boundary\r\n";
				$to_send .= "Content-type: $mime_type; name=$file_name\r\n";
				$to_send .= "Content-disposition: attachment; filename=$file_name\r\n"; 
				$to_send .= "Content-transfer-encoding: base64\r\n\r\n"; 

				$to_send .= "$read\r\n";
			}
			
    		$to_send .= "\r\n--$boundary--\r\n.\r\n";
    	}
		//echo $to_send;exit;
		if($this->doCommand($to_send,'250') === false) 
		{
			fclose($this->fp);
			return false;    
		}
		
		//發信完畢，關閉連接
		if($this->doCommand("quit\r\n",'221') === false)    //关闭连接
		{
			fclose($this->fp);
			return false;    
		}

		return true;
	}
}


/*///example:
set_time_limit(0);
$content = <<< MSG
恭喜你,成功的发送了附件\r\n\r\n谢谢\r\n\r\nhttp://www.jerryjiang.net
MSG;
$mail_model = new SendMail("mail.clschina.com",25,"customer_service@clschina.com","111111");  //声明类
//$mail_model->addAttachment('./test.doc');    //添加附件
if(!$mail_model->send("customer_service@clschina.com","大地之舞","jerryjiang15@163.com","大地之舞网友","测试",$content,'txt','utf-8'))
{
	$mail_model->debug();
}
else 
{
	echo "send succeed!";
}*/
?>